package com.cloud.gateway.core;

import com.cloud.gateway.context.VersionHolder;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class RibbonServerSelector extends RibbonLoadBalancerClient {

    @Autowired
    private VersionHolder versionHolder;

    @Autowired
    private DiscoveryClient discoveryClient;

    private Map<String, Integer> selectIndexMap = new HashMap<>();

    public RibbonServerSelector(SpringClientFactory clientFactory) {
        super(clientFactory);
    }

    @Override
    protected Server getServer(String serviceId) {
        ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
        if (loadBalancer == null) {
            return null;
        }

        String version = versionHolder.get();
        if (version != null) {
            List<ServiceInstance> matchInstanceList = new ArrayList<>();
            List<ServiceInstance> instanceList = discoveryClient.getInstances(serviceId);
            for (ServiceInstance instance : instanceList) {
                String instanceVersion = instance.getMetadata().get("version");
                if (StringUtils.isEmpty(instanceVersion) || instanceVersion.equals("undefined") || !instanceVersion.equals(version)) {
                    continue;
                }
                matchInstanceList.add(instance);
            }
            if (matchInstanceList.size() > 0) {
                //选择服务器
                ServiceInstance instance = selectInstance(serviceId, matchInstanceList);
                List<Server> servers = loadBalancer.getAllServers();
                for (Server server : servers) {
                    if (server.getHost().equals(instance.getHost()) && server.getPort() == instance.getPort()) {
                        return server;
                    }
                }
            }
        }
        return loadBalancer.chooseServer("default");
    }

    private synchronized ServiceInstance selectInstance(String serviceId, List<ServiceInstance> matchInstanceList) {
        Integer selectIndex = selectIndexMap.get(serviceId);
        if (selectIndex == null || selectIndex == Short.MAX_VALUE) {
            selectIndex = 0;
        }
        selectIndexMap.put(serviceId, ++selectIndex);
        return matchInstanceList.get(selectIndex % matchInstanceList.size());
    }

}
